﻿/*
* 创建者：LIYINFAI
* 创建时间：2023/10/24 9:35:26
* 描述：
* --------------------------------------
* 修改说明：
* --------------------------------------
*/
using CommonLibrary.Forms;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using static SQLiteEx.SQLite3;

namespace CommonLibrary
{
    /// <summary>
    /// 插件类型
    /// </summary>
    public class PluginEntity
    {
        /// <summary>
        /// 类名
        /// </summary>
        public string ClassName { get; set; }
        /// <summary>
        /// 插件接口
        /// </summary>
        public IPlugin Plugin { get; set; }
    }
    /// <summary>
    /// 更新Icon
    /// </summary>
    /// <param name="image"></param>
    public delegate void UpdateCustomBitmapDelegate(Bitmap image);
    /// <summary>
    /// 更新版本号
    /// </summary>
    /// <param name="version"></param>
    public delegate void UpdateCustomVersionDelegate(string version);
    
    /// <summary>
    /// 插件管理器
    /// </summary>
    public class PluginManager
    {
        /// <summary>
        /// 更新Icon代理
        /// </summary>
        public static UpdateCustomBitmapDelegate UpdateAppIcon { get; set; }
        /// <summary>
        /// 更新版本号代理
        /// </summary>
        public static UpdateCustomVersionDelegate UpdateAppVersion { get; set; }
        /// <summary>
        /// 插件目录
        /// </summary>
        public readonly static string CONFIG_FILE_PATH = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");
        /// <summary>
        /// 该文件作为是否需要重新加载插件的标记，发现有该文件则需要重新加载，加载完毕后删除该文件
        /// </summary>
        public readonly static string RELOAD_REQUIED_FILE_PATH = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "rrfp");
        /// <summary>
        /// 懒加载实例
        /// </summary>
        private static Lazy<PluginManager> _instance = new Lazy<PluginManager>(() => new PluginManager());
        /// <summary>
        /// 公开实例对象
        /// </summary>
        public static PluginManager Instance { get { return _instance.Value; } }
        /// <summary>
        /// 插件内容
        /// </summary>
        private List<PluginEntity> mPlugins = new List<PluginEntity>();
        /// <summary>
        /// 构造函数
        /// </summary>
        private PluginManager()
        {
            Load();
            CheckReloadContinous();
        }
        /// <summary>
        /// 析构函数
        /// </summary>
        ~PluginManager()
        {
        }
        /// <summary>
        /// 检查是否需要重新加载
        /// </summary>
        private void CheckReloadContinous()
        {
            new Thread(() =>
            {
                while (GlobalStatus.PROGRAM == EAppStatus.RUN)
                {
                    if (File.Exists(RELOAD_REQUIED_FILE_PATH))
                    {
                        Load();
                        File.Delete(RELOAD_REQUIED_FILE_PATH);
                        LogHelper.Debug("已重新加载插件内容");
                    }
                    Thread.Sleep(1000);
                }
            })
            { IsBackground = true }.Start();
        }
        /// <summary>
        /// 锁，用于加载时停止一切调用行为
        /// </summary>
        private object LOAD_LOCK = new object();
        /// <summary>
        /// 是否允许执行插件方法
        /// </summary>
        private bool mCanExcute = true;
        /// <summary>
        /// 获取是否允许执行插件方法
        /// </summary>
        public bool CanExcute
        {
            get
            {
                lock (LOAD_LOCK)
                {
                    return mCanExcute;
                }
            }
        }
        /// <summary>
        /// 执行插件方法(异步)
        /// </summary>
        public async Task<string> ExcuteAsync(PluginParamEntity pluginParam)
        {
            string result = "";
            await Task.Run(() =>
              {
                  result = ExcuteJob(pluginParam);
              });
            return result;
        }
        /// <summary>
        /// 执行插件方法(同步)
        /// </summary>
        public string Excute(PluginParamEntity pluginParam)
        {
            return ExcuteJob(pluginParam);
        }
        /// <summary>
        /// 执行插件方法(同步)
        /// </summary>
        public string Excute(string tag, string identity, string paramString = "")
        {
            var pluginParam = PluginParam.Instance().GetPluginParam(tag, identity, paramString);
            return ExcuteJob(pluginParam);
        }
        /// <summary>
        /// 获取窗体
        /// </summary>
        public HWFrmWithTitle GetForm(PluginParamEntity pluginParam)
        {
            return ExcuteGetFormJob(pluginParam);
        }
        /// <summary>
        /// 获取窗体
        /// </summary>
        public HWFrmWithTitle GetForm(string tag, string identity, string paramString = "")
        {
            var pluginParam = PluginParam.Instance().GetPluginParam(tag, identity, paramString);
            return GetForm(pluginParam);
        }
        /// <summary>
        /// 执行插件方法
        /// </summary>
        private string ExcuteJob(PluginParamEntity pluginParam)
        {
            string result = string.Empty;
            if (CanExcute)
            {
                if (pluginParam != null)
                {
                    try
                    {
                        var p = this.mPlugins.Find(v => v.ClassName.ToLower().Equals(pluginParam.ClassName.ToLower()));
                        if (p != null)
                        {
                            LogHelper.Info($"【ExcuteJob】 开始，参数：{CommonHelper.GetJsonString(pluginParam, Newtonsoft.Json.Formatting.None)}，{pluginParam.ParamString}");
                            result = p.Plugin.Excute(pluginParam);
                            LogHelper.Info($"【ExcuteJob】 结束，参数：{CommonHelper.GetJsonString(pluginParam, Newtonsoft.Json.Formatting.None)}");
                        }
                    }
                    catch (Exception ex)
                    {
                        LogHelper.Error(ex);
                    }
                }
                else
                {
                    throw new ArgumentException("没有合适的方法");
                }
            }
            else
            {
                throw new ArgumentException("当前不允许执行任何方法");
            }
            return result;
        }
        /// <summary>
        /// 获取窗体方法
        /// </summary>
        private HWFrmWithTitle ExcuteGetFormJob(PluginParamEntity pluginParam)
        {
            HWFrmWithTitle result = null;
            if (CanExcute)
            {
                if (pluginParam != null)
                {
                    try
                    {
                        var p = this.mPlugins.Find(v => v.ClassName.ToLower().Equals(pluginParam.ClassName.ToLower()));
                        if (p != null)
                        {
                            LogHelper.Info($"【ExcuteJob】 开始，参数：{CommonHelper.GetJsonString(pluginParam, Newtonsoft.Json.Formatting.None)}，{pluginParam.ParamString}");
                            result = p.Plugin.GetForm(pluginParam);
                            LogHelper.Info($"【ExcuteJob】 结束，参数：{CommonHelper.GetJsonString(pluginParam, Newtonsoft.Json.Formatting.None)}");
                        }
                    }
                    catch (Exception ex)
                    {
                        LogHelper.Error(ex);
                    }
                }
                else
                {
                    throw new ArgumentException("没有合适的方法");
                }
            }
            else
            {
                throw new ArgumentException("当前不允许执行任何方法");
            }
            return result;
        }
        /// <summary>
        /// 退出插件管理器
        /// </summary>
        public void Exit()
        {
            this.mCanExcute = false;
        }
        private void HandleIcon()
        {
            try
            {
                var p = this.mPlugins.Find(v => v.ClassName.ToLower().Equals("app"));
                if (p != null)
                {
                    var icon = p.Plugin.GetBitmap();
                    if (UpdateAppIcon != null)
                    {
                        UpdateAppIcon(icon);
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }
        private void HandleVersion()
        {
            try
            {
                var p = this.mPlugins.Find(v => v.ClassName.ToLower().Equals("version"));
                if (p != null)
                {
                    var version = p.Plugin.Excute(new PluginParamEntity()
                    {
                        Identity = "VERSION_VERSION"
                    });
                    if (UpdateAppVersion != null)
                    {
                        UpdateAppVersion(version);
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }
        /// <summary>
        /// 加载插件内容
        /// </summary>
        private void Load()
        {
            lock (LOAD_LOCK)
            {
                this.mCanExcute = false;
                try
                {
                    CommonHelper.CheckDirectory(CONFIG_FILE_PATH);
                    this.mPlugins.Clear();
                    foreach (var dll in Directory.GetFiles(CONFIG_FILE_PATH, "*.dll"))
                    {
                        byte[] bytes = File.ReadAllBytes(dll);
                        Assembly assembly = Assembly.Load(bytes);
                        foreach (var type in assembly.GetTypes())
                        {
                            if (type.GetInterfaces().Contains(typeof(IPlugin)))
                            {
                                mPlugins.Add(new PluginEntity()
                                {
                                    ClassName = type.Name,
                                    Plugin = (IPlugin)assembly.CreateInstance(type.FullName)
                                });
                            }
                        }
                    }
                    HandleIcon();
                    HandleVersion();
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
                finally
                {
                    this.mCanExcute = true;
                }
            }
        }
    }
}
